package cn;


import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;

import cn.util.ScanLoaderUtil;

public  class AppClassLoader {

    private final  static Set<String> sClassPaths = new HashSet<>();

    private synchronized   void  loadClassFiles(String classpath){
        File libfile = new File(classpath);
        if (!libfile.exists()) {
            System.out.println("jar file not found."+libfile);
            return;
        }
        Stack<File> stack = new Stack<>();
        stack.push(libfile);

        do{
            if(stack.empty()) break;
            File pop = stack.pop();
            if(isJavaFile(pop) || isSoLibrary(pop)) {
                String absPath = pop.getAbsolutePath();
                if(absPath.endsWith(".jar")){
                    loadClassPathClasses(pop);
                }else if(absPath.endsWith(".class")){
                    String absClasspath = ScanLoaderUtil.getClassPath(absPath);
                    if(absClasspath!=null){
                        loadClassPathClasses(new File(absClasspath));
                    }
                }
            }else if(pop.isDirectory()){
                loadClassPathClasses(pop);
            }

        }while (true);


    }

    private boolean isSoLibrary(File pop) {
        if(!pop.isFile()) return false;
        String absolutePath = pop.getAbsolutePath();
        return absolutePath.endsWith(".so");
    }

    private boolean isJavaFile(File pop) {

        if(!pop.isFile()) return false;
        String absolutePath = pop.getAbsolutePath();
        return absolutePath.endsWith(".class") || absolutePath.endsWith(".jar");
    }

    public   synchronized  void  addClassPath(String classPath){
        sClassPaths.add(classPath);
    }


    private static void loadClassPathClasses(File jarFile) {
        //获取类加载器的addURL方法，准备动态调用
        Method method = null;
        try {
            method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
        } catch (NoSuchMethodException | SecurityException e1) {
            e1.printStackTrace();
        }
        // 获取方法的访问权限，保存原始值
        boolean accessible = method.isAccessible();
        try {
            //修改访问权限为可写
            if (accessible == false) {
                method.setAccessible(true);
            }
            // 获取系统类加载器

            URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
            //获取jar文件的url路径
            URL url = jarFile.toURI().toURL();
            //jar路径加入到系统url路径里
            method.invoke(classLoader, url);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //回写访问权限
            method.setAccessible(accessible);
        }
    }

    public void startLoadClasses() {
        if(sClassPaths.size()==0) return;
        for (String classPath : sClassPaths){
            if(classPath==null || classPath.length()==0) continue;
            loadClassFiles(classPath);
        }

    }

    public static ClassLoader getLoader(){
        return ClassLoader.getSystemClassLoader();
    }




}
